﻿using Admin.Application.Const;
using Admin.Application.DynamicApi.System.Menu.Dto;
using Admin.Application.DynamicApi.System.Role;
using Admin.Application.DynamicApi.System.User;
using Admin.Database.Enums;
using Admin.Database.Model;
using Admin.Database.SeedData;
using Framework.Core;
using Framework.Core.CustomException;
using Framework.DI;
using Framework.DynamicApiController;
using Framework.SqlSugar;
using Framework.SqlSugar.Repository;
using Mapster;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Admin.Application.DynamicApi.System.Menu
{
	/// <summary>
	/// 菜单服务 🧩
	/// </summary>
	[Service]
	public class SysMenuService: ISelfTransientAutoInject
	{
		private readonly SqlSugarRepository<SysMenu> _sysMenuRep;
		private readonly SysRoleMenuService _sysRoleMenuService;
		private readonly SysUserRoleService _sysUserRoleService;
		private readonly CacheHelp _sysCacheService;
		private readonly UserManager _userManager;

		public SysMenuService(SqlSugarRepository<SysMenu> sysMenuRep, SysUserRoleService sysUserRoleService,
			SysRoleMenuService sysRoleMenuService,CacheHelp sysCacheService,UserManager userManager)
		{
			_sysMenuRep = sysMenuRep;
			_sysUserRoleService = sysUserRoleService;
			_userManager = userManager;
			_sysCacheService = sysCacheService;
			_sysRoleMenuService = sysRoleMenuService;
		}

		/// <summary>
		/// 获取登录菜单树 🔖
		/// </summary>
		/// <returns></returns>
		[DisplayName("获取登录菜单树")]
		public async Task<List<MenuOutput>> GetLoginMenuTree()
		{
			var query = _sysMenuRep.AsQueryable();
			if (_userManager.SuperAdmin)
			{
				var menuList = await query.Where(u => u.Type != MenuTypeEnum.Btn && u.Status == StatusEnum.Enable)
					.OrderBy(u => new { u.OrderNo, u.Id })
					.ToTreeAsync(u => u.Children, u => u.Pid, 0);
				return menuList.Adapt<List<MenuOutput>>();
			}

			var menuIdList = await GetMenuIdList();
			var menuTree = await query.Where(u => u.Type != MenuTypeEnum.Btn && u.Status == StatusEnum.Enable)
				.OrderBy(u => new { u.OrderNo, u.Id }).ToTreeAsync(u => u.Children, u => u.Pid, 0, menuIdList.Select(d => (object)d).ToArray());
			return menuTree.Adapt<List<MenuOutput>>();
		}

		/// <summary>
		/// 获取菜单列表 🔖
		/// </summary>
		/// <returns></returns>
		[DisplayName("获取菜单列表")]
		public async Task<List<SysMenu>> GetList([FromQuery] MenuInput input)
		{
			var menuIdList = _userManager.SuperAdmin ? new List<long>() : await GetMenuIdList();
			var query = _sysMenuRep.AsQueryable();

			// 有筛选条件时返回list列表（防止构造不出树）
			if (!string.IsNullOrWhiteSpace(input.Title) || input.Type is > 0)
			{
				return await query.WhereIF(!string.IsNullOrWhiteSpace(input.Title), u => u.Title.Contains(input.Title))
					.WhereIF(input.Type is > 0, u => u.Type == input.Type)
					.WhereIF(menuIdList.Count > 1, u => menuIdList.Contains(u.Id))
					.OrderBy(u => new { u.OrderNo, u.Id }).Distinct().ToListAsync();
			}

			return _userManager.SuperAdmin ?
				await query.OrderBy(u => new { u.OrderNo, u.Id }).Distinct().ToTreeAsync(u => u.Children, u => u.Pid, 0) :
				await query.OrderBy(u => new { u.OrderNo, u.Id }).Distinct().ToTreeAsync(u => u.Children, u => u.Pid, 0, menuIdList.Select(d => (object)d).ToArray()); // 角色菜单授权时
		}

		/// <summary>
		/// 增加菜单 🔖
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		[HttpPost]
		[DisplayName("增加菜单")]
		public async Task<long> AddMenu(AddMenuInput input)
		{
			var query = _sysMenuRep.AsQueryable();

			var isExist = input.Type != MenuTypeEnum.Btn
				? await query.AnyAsync(u => u.Title == input.Title && u.Pid == input.Pid)
				: await query.AnyAsync(u => u.Permission == input.Permission);
			if (isExist) throw new CustomException("菜单已存在");

			if (!string.IsNullOrWhiteSpace(input.Name) && await query.AnyAsync(u => u.Name == input.Name)) throw new CustomException("路由名称重复");

			if (input.Pid != 0 && await query.AnyAsync(u => u.Id == input.Pid && u.Type == MenuTypeEnum.Btn)) throw new CustomException("父节点不能为按钮类型");

			// 校验菜单参数
			var sysMenu = input.Adapt<SysMenu>();
			CheckMenuParam(sysMenu);

			// 保存租户菜单权限
			await _sysMenuRep.InsertAsync(sysMenu);

			// 清除缓存
			DeleteMenuCache();

			return sysMenu.Id;
		}

		/// <summary>
		/// 更新菜单 🔖
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		[HttpPost]
		[DisplayName("更新菜单")]
		public async Task UpdateMenu(UpdateMenuInput input)
		{
			if (!_userManager.SuperAdmin && new SysMenuSeedData().HasData().Any(u => u.Id == input.Id)) throw new CustomException("系统菜单禁止修改");

			if (input.Id == input.Pid) throw new CustomException("禁止本节点与父节点相同");
			var query = _sysMenuRep.AsQueryable();

			var isExist = input.Type != MenuTypeEnum.Btn
				? await query.AnyAsync(u => u.Title == input.Title && u.Type == input.Type && u.Pid == input.Pid && u.Id != input.Id)
				: await query.AnyAsync(u => u.Permission == input.Permission && u.Id != input.Id);
			if (isExist) throw new CustomException("菜单已存在");

			if (!string.IsNullOrWhiteSpace(input.Name) && await query.AnyAsync(u => u.Id != input.Id && u.Name == input.Name)) throw new CustomException("路由名称重复");

			if (input.Pid != 0 && await query.AnyAsync(u => u.Id == input.Pid && u.Type == MenuTypeEnum.Btn)) throw new CustomException("父节点不能为按钮类型");

			// 校验菜单参数
			var sysMenu = input.Adapt<SysMenu>();
			CheckMenuParam(sysMenu);

			await _sysMenuRep.AsUpdateable(sysMenu).ExecuteCommandAsync();

			// 清除缓存
			DeleteMenuCache();
		}

		/// <summary>
		/// 删除菜单 🔖
		/// </summary>
		/// <param name="input"></param>
		/// <returns></returns>
		[UnitOfWork]
		[HttpPost]
		[DisplayName("删除菜单")]
		public async Task DeleteMenu(DeleteMenuInput input)
		{
			if (!_userManager.SuperAdmin && new SysMenuSeedData().HasData().Any(u => u.Id == input.Id)) throw new CustomException("系统菜单禁止删除");

			var menuTreeList = await _sysMenuRep.AsQueryable().ToChildListAsync(u => u.Pid, input.Id);
			var menuIdList = menuTreeList.Select(u => u.Id).ToList();

			await _sysMenuRep.DeleteAsync(u => menuIdList.Contains(u.Id));

			// 级联删除角色菜单数据
			await _sysRoleMenuService.DeleteRoleMenuByMenuIdList(menuIdList);

			// 清除缓存
			DeleteMenuCache();
		}

		/// <summary>
		/// 增加和编辑时检查菜单数据
		/// </summary>
		/// <param name="menu"></param>
		private static void CheckMenuParam(SysMenu menu)
		{
			var permission = menu.Permission;
			if (menu.Type == MenuTypeEnum.Btn)
			{
				menu.Name = null;
				menu.Path = null;
				menu.Component = null;
				menu.Icon = null;
				menu.Redirect = null;
				menu.OutLink = null;
				menu.IsHide = false;
				menu.IsKeepAlive = true;
				menu.IsAffix = false;
				menu.IsIframe = false;

				if (string.IsNullOrEmpty(permission)) throw new CustomException("权限标识格式为空");
				if (!permission.Contains(':')) throw new CustomException("权限标识格式错误 如xxx:xxx");
			}
			else
			{
				menu.Permission = null;
			}
		}

		/// <summary>
		/// 获取用户拥有按钮权限集合（缓存） 🔖
		/// </summary>
		/// <returns></returns>
		[DisplayName("获取按钮权限集合")]
		public async Task<List<string>> GetOwnBtnPermList()
		{
			var userId = _userManager.UserId;
			var permissions = _sysCacheService.Get<List<string>>(CacheConst.KeyUserButton + userId);
			if (permissions != null) return permissions;

			var menuIdList = _userManager.SuperAdmin ? new() : await GetMenuIdList();

			permissions = await _sysMenuRep.AsQueryable().Where(u => u.Type == MenuTypeEnum.Btn)
				.WhereIF(menuIdList.Count > 0, u => menuIdList.Contains(u.Id))
				.Select(u => u.Permission).ToListAsync();


			_sysCacheService.Set(CacheConst.KeyUserButton + userId, permissions, TimeSpan.FromDays(7));

			return permissions;
		}

		/// <summary>
		/// 获取系统所有按钮权限集合（缓存）
		/// </summary>
		/// <returns></returns>
		[NonAction]
		public async Task<List<string>> GetAllBtnPermList()
		{
			var permissions = _sysCacheService.Get<List<string>>(CacheConst.KeyUserButton + 0);
			if (permissions != null && permissions.Count != 0) return permissions;

			permissions = await _sysMenuRep.AsQueryable()
				.Where(u => u.Type == MenuTypeEnum.Btn)
				.Select(u => u.Permission).ToListAsync();
			_sysCacheService.Set(CacheConst.KeyUserButton + 0, permissions);

			return permissions;
		}

		/// <summary>
		/// 清除菜单和按钮缓存
		/// </summary>
		[NonAction]
		public void DeleteMenuCache()
		{
			// _sysCacheService.RemoveByPrefixKey(CacheConst.KeyUserMenu);
			_sysCacheService.RemoveByPrefixKey(CacheConst.KeyUserButton);
		}

		/// <summary>
		/// 获取当前用户菜单Id集合
		/// </summary>
		/// <returns></returns>
		[NonAction]
		public async Task<List<long>> GetMenuIdList()
		{
			var roleIdList = await _sysUserRoleService.GetUserRoleIdList(_userManager.UserId);
			return await _sysRoleMenuService.GetRoleMenuIdList(roleIdList);
		}

		/// <summary>
		/// 排除前端存在全选的父级菜单
		/// </summary>
		/// <returns></returns>
		[NonAction]
		public async Task<List<long>> ExcludeParentMenuOfFullySelected(List<long> menuIds)
		{
			// 获取当前用户菜单
			var query = _sysMenuRep.AsQueryable();
			var menuList = await query.ToListAsync();

			// 排除列表，防止前端全选问题
			var exceptList = new List<long>();
			foreach (var id in menuIds)
			{
				// 排除按钮菜单
				if (menuList.Any(u => u.Id == id && u.Type == MenuTypeEnum.Btn)) continue;

				// 如果没有子集或有全部子集权限
				var children = menuList.ToChildList(u => u.Id, u => u.Pid, id, false).ToList();
				if (children.Count == 0 || children.All(u => menuIds.Contains(u.Id))) continue;

				// 排除没有全部子集权限的菜单
				exceptList.Add(id);
			}
			return menuIds.Except(exceptList).ToList();
		}
	}
}
